#include "rtspsession.h"
#include <QDebug>
//#include <QtEndian>  // 必须添加的头文件
#include <QByteArray>
#include <QDataStream>
#include "rtpreceiver.h"
#include "filewriter.h"

RtspSession::RtspSession(QTcpSocket *socket, QObject *parent)
    : QObject(parent), m_socket(socket)
{
    connect(m_socket, &QTcpSocket::readyRead, this, &RtspSession::readClient);
}

//处理客户端RTSP请求
void RtspSession::readClient()
{
    QByteArray data = m_socket->readAll();

    qInfo() << "readClient:";
    qInfo() << data;

    //推流过程
    //‌OPTION‌：客户端查询服务器支持的方法‌
    //ANNOUNCE‌：客户端发送媒体描述信息（如SDP格式）‌   //与拉流使用不同的接口 a=setup:sendonly// 推流模式（仅发送）a=rtpmap:34 MP4V/90000  // 推流编码格式
    //‌‌SETUP‌：建立RTSP会话，协商传输参数（如RTP端口）‌  //约定的端口与拉流端口不同需要区分  ，使用与拉流不同的Session，需要区分
    //‌RECORD‌：客户端请求开始推送数据流‌  //‌RTP传输‌：通过UDP/TCP推送音视频数据包‌
    //‌TEARDOWN‌：终止会话‌
    //客户端发送开始推流

    //若输入文件为H.264编码，VLC会直接提取NAL单元并封装到输出流中‌
    //若需转码，VLC会解码原始NAL单元，重新编码为新的NAL单元序列‌


    // 处理RTSP命令
    if (data.startsWith("OPTIONS"))
    {
        int cseqPos = data.indexOf("CSeq:");
        int cseqEnd = data.indexOf("\r\n", cseqPos);
        QByteArray cseqValue = data.mid(cseqPos+5, cseqEnd-(cseqPos+5)).trimmed();

        // 构建完整响应
        QByteArray response = "RTSP/1.0 200 OK\r\n"
                              "CSeq: " + cseqValue + "\r\n"
                              "Public: OPTIONS, ANNOUNCE, SETUP, TEARDOWN, RECORD\r\n"
                              "Server: QtRTSP/1.0\r\n\r\n";

        qInfo() << "OPTIONS response:";
        qInfo() << response;
        m_socket->write(response);
    }
    else if(data.startsWith("ANNOUNCE"))
    {
         qInfo() << "ANNOUNCE‌ ";
        //推流会话请求 ，包含SDP信息
        /*
        "ANNOUNCE rtsp://127.0.0.1:8554/ RTSP/1.0\r\n
        Content-Type: application/sdp\r\n
        CSeq: 2\r\n
        User-Agent: Lavf58.11.101\r\n
        Content-Length: 288\r\n\r\n
        v=0\r\n
        o=- 0 0 IN IP4 127.0.0.1\r\n
        s=No Name\r\n
        c=IN IP4 127.0.0.1\r\n
        t=0 0\r\n
        a=tool:libavformat 58.11.101\r\n
        m=video 0 RTP/AVP 96\r\n
        a=rtpmap:96 H264/90000\r\n
        a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAC6zZQgRoQAAAAwBAAAAPA8UKZYA=,aOvjyyLA; profile-level-id=64000B\r\n
        a=control:streamid=0\r\n"
        */
        //抓包显示已接收完成

        //rtsp://127.0.0.1:8554/  推流目标RTSP服务器地址
        //验证sdp格式 服务器需返回200 OK  Session

        int contentStart = data.indexOf("\r\n\r\n") + 4;
        QByteArray sdpContent = data.mid(contentStart);

        // 验证SDP格式
        if (!sdpContent.startsWith("v="))
        {
           // sendResponse(socket, "400 Bad Request", "Invalid SDP format\r\n");
            qInfo() << "ANNOUNCE‌ error";
            return;
        }




        // 1. 定位参数起始位置
        int startPos = sdpContent.indexOf("sprop-parameter-sets=");
        if (startPos == -1)
        {
            qDebug() << "Parameter not found";
        }
        startPos += 20; // 跳过"sprop-parameter-sets="长度

        // 2. 定位参数结束位置（分号或行尾）
        int endPos = sdpContent.indexOf(';', startPos);
        if (endPos == -1) {
            endPos = sdpContent.indexOf('\r', startPos);
            if (endPos == -1) endPos = sdpContent.length();
        }

        // 3. 提取完整参数值
        m_SDP_SPS = sdpContent.mid(startPos, endPos - startPos).trimmed();


        int cseqPos = data.indexOf("CSeq:");
        int cseqEnd = data.indexOf("\r\n", cseqPos);
        QByteArray cseqValue = data.mid(cseqPos+5, cseqEnd-(cseqPos+5)).trimmed();


        //a=setup:sendonly// 推流模式（仅发送）a=rtpmap:34 MP4V/90000  // 推流编码格式

        QByteArray response = "RTSP/1.0 200 OK\r\n"
                              "CSeq: " + cseqValue + "\r\n"
                              "Content-Type: application/sdp\r\n"
                              "Session: 87654321\r\n\r\n";

        qInfo() << "ANNOUNCE‌ response:";
        qInfo() << response;

        m_socket->write(response);

    }
    else if (data.startsWith("SETUP"))
    {
        //推流会话请求
        /*
        "SETUP rtsp://127.0.0.1:8554//streamid=0 RTSP/1.0\r\n
        Transport: RTP/AVP/UDP;unicast;client_port=34596-34597;mode=record\r\n
        CSeq: 3\r\n
        User-Agent: Lavf58.11.101\r\n
        Session: 87654321\r\n\r\n"
        */

        //client_port始终指向‌发起请求的客户端端口‌，无论推流或拉流场景均遵循此规则
        //*client_port 这里提议了建立连接的端口, 服务器返回 200 OK，即‌接受提议‌，后面RTP数据传输使用指定的端口
        //*返回 Session 给客户端,表明连接建立完成，会话初始化成功,这里指定为 12345678
        //*Session: 12345678 需要server指定，在SETUP请求建立传输通道时返回给客户端

        int cseqPos = data.indexOf("CSeq:");
        int cseqEnd = data.indexOf("\r\n", cseqPos);
        QByteArray cseqValue = data.mid(cseqPos+5, cseqEnd-(cseqPos+5)).trimmed();

        //设置约定的端口(拉流模式下)
        //server_port：服务器发送RTP/RTCP数据的端口（如5000-5001）
        //client_port：确认使用客户端提议的端口（61786-61787）
        //双向端口绑定要求‌，RTSP规范要求SETUP响应必须明确返回server_port参数，
        //用于标识服务器端绑定的RTP/RTCP端口对（偶数端口为RTP，相邻奇数端口为RTCP）

        //推流模式下则是 server接收client发送的RTP数据

        //从请求获取client_port的两个端口，相邻两个端口一偶数一奇数，偶数用于RTP传输，奇数用于RTCP
        QString strdata(data);
        parseClientPort(strdata);
        //指定server发送RTP/RTCP的两个端口，相邻两个端口一偶数一奇数，偶数用于RTP传输，奇数用于RTCP
        m_serverport1 = 9000;
        m_serverport2 = 9001;

        QString strclientport1 = QString::number(m_clientport1);
        QString strclientport2 = QString::number(m_clientport2);
        QString strserverport1 = QString::number(m_serverport1);
        QString strserverport2 = QString::number(m_serverport2);

        QByteArray strclient_port = "client_port=" + strclientport1.toUtf8() + "-" + strclientport2.toUtf8() + ";" ;
        QByteArray strserver_port = "server_port=" + strserverport1.toUtf8() + "-" + strserverport2.toUtf8() + ";";
        QByteArray response = "RTSP/1.0 200 OK\r\n"
                              "CSeq: " + cseqValue + "\r\n"
                              "Transport: RTP/AVP;unicast;"+ strclient_port + strserver_port  +"\r\n"
                              "Session: 87654321\r\n\r\n";

        qInfo() << "SETUP response:";
        qInfo() << response;
        m_socket->write(response);

    }
    else if(data.startsWith("TEARDOWN"))
    {
        int cseqPos = data.indexOf("CSeq:");
        int sessionPos = data.indexOf("Session:");
        QByteArray cseq = data.mid(cseqPos + 5, data.indexOf("\r\n", cseqPos) - (cseqPos + 5)).trimmed();
        QByteArray sessionId = data.mid(sessionPos + 8, data.indexOf("\r\n", sessionPos) - (sessionPos + 8)).trimmed();

        // 发送响应
        QByteArray response = "RTSP/1.0 200 OK\r\n"
                              "CSeq: " + cseq + "\r\n"
                              "Session: " + sessionId + "\r\n\r\n";

        qInfo() << "TEARDOWN response:";
        qInfo() << response;
        m_socket->write(response);

        // 释放资源（如关闭RTP通道、清除会话状态）
        //releaseSessionResources(sessionId);
    }
    else if(data.startsWith("RECORD"))
    {
        //推流会话请求, 开始发送数据请求
        /*
        "RECORD rtsp://127.0.0.1:8554/ RTSP/1.0\r\n
        Range: npt=0.000-\r\n
        CSeq: 4\r\nUser-Agent: Lavf58.11.101\r\n
        Session: 87654321\r\n\r\n"
        */

        int cseqPos = data.indexOf("CSeq:");
        int cseqEnd = data.indexOf("\r\n", cseqPos);
        QByteArray cseqValue = data.mid(cseqPos+5, cseqEnd-(cseqPos+5)).trimmed();
        QByteArray response = "RTSP/1.0 200 OK\r\n"
                              "CSeq: " + cseqValue + "\r\n"
                              "Session: 87654321\r\n"
                              "Range: npt=0.000-\r\n"
                               "\r\n";


        qInfo() << "RECORD‌ response:";
        qInfo() << response;
        m_socket->write(response);

        //开启文件写入线程

        FileWriter * writer = new FileWriter();  // 文件写入线程实例
        writer->start();     // 先启动写入线程

        //开启接收器，接收推流数据
        RtpReceiver* receiver = new RtpReceiver(m_serverport1, m_SDP_SPS);
        receiver->start();

        connect(receiver, &RtpReceiver::writefile, writer, &FileWriter::enqueueNalu);

    }
}

//从请求中获取client_port，并缓存
void RtspSession::parseClientPort(const QString &rtspHeader)
{
    // 查找Transport行
    int transportPos = rtspHeader.indexOf("Transport:");
    if (transportPos == -1)
    {
        qWarning() << "Transport header not found";
        return;
    }

    // 提取client_port=后面的部分
    int clientPos = rtspHeader.indexOf("client_port=", transportPos);
    if (clientPos == -1)
    {
        qWarning() << "client_port attribute not found";
        return;
    }

    QString portStr = rtspHeader.mid(clientPos + 12); // 跳过client_port=前缀
    int hyphenPos = portStr.indexOf('-');
    if (hyphenPos == -1)
    {
        qWarning() << "Invalid port format (missing hyphen)";
        return;
    }

    QString port1Str = portStr.left(hyphenPos);
    QString port2Str = portStr.mid(hyphenPos + 1);

    // 转换为整数
    bool ok1, ok2;
    m_clientport1 = port1Str.toUShort(&ok1);
    m_clientport2 = port2Str.toUShort(&ok2);

    if (ok1 && ok2)
    {
        qDebug() << "Extracted ports:" << m_clientport1 << "and" << m_clientport2;
    }
    else
    {
        qWarning() << "Invalid port numbers";
    }
}

